﻿using System;
using System.Collections.Generic;
using BlobNet.Base.DataProviders;

namespace BlobNet.Base.Collections.List
{
    [Serializable]
    internal class ValueTypePersistentList<TType> : PersistentListBase<TType> //where TType:struct 
    {
        public ValueTypePersistentList(BlobDomain blobDomain, Guid collectionId)
            : this(blobDomain, collectionId,null)
        {
        }

        public ValueTypePersistentList(BlobDomain blobDomain, Guid collectionId, IEnumerable<TType> source)
            : base(blobDomain, collectionId, source)
        {
        }

        #region Overrides of ShPersistentListBase<TType>

        public override TType this[int index]
        {
            get
            {
                if ((uint) index >= (uint) Count)
                    throw new ArgumentOutOfRangeException();
                ITupleList listItem = DataProvider.RetrieveListItem(Domain.EntityId, EntityId, index);

                TType result;

                result = listItem == null ? default(TType) : (TType) listItem.Value;

                return result;
            }
            set
            {
                if ((uint) index >= (uint) Count)
                    throw new ArgumentOutOfRangeException();

                TupleList tuple = null;

                tuple = new TupleList(index, EntityId, value.GetType().FullName, value);


                //reorders the indexes
                DataProvider.RemoveEntityFromCollection(Domain.EntityId, EntityId, index);

                DataProvider.AddEntityToCollection(Domain.EntityId, EntityId, index,
                                                   tuple.FullyQualifiedType, tuple.Value);
                ++Version;
            }
        }

        public ValueTypePersistentList<TType> GetRange(int index, int count)
        {
            Guid destId = Guid.NewGuid();
            DataProvider.CopyListRange(Domain.EntityId, EntityId, destId, index, count);

            return new ValueTypePersistentList<TType>(Domain, destId);
        }

        public override void Add(TType item)
        {
            int index = Count;

            TupleList tuple = null;
            //boxing and save
            //Guid addObject = DataProvider.AddObject(BlobDomain.EntityId, item);
            tuple = new TupleList(index, EntityId, item.GetType().FullName, item);


            DataProvider.AddEntityToCollection(Domain.EntityId, EntityId, tuple.Position,
                                               tuple.FullyQualifiedType, tuple.Value);
            ++Version;
        }

        public override bool Contains(TType item)
        {
            bool result = false;
            //TODO: optimize to get it from query count

            int count = Count;
            for (int index = 0; index < count; index++) //TODO: no time but needs optimization
            {
                if (Equals(item, this[index]))
                {
                    result = true;
                    break;
                }
            }

            return result;
        }

        public override int IndexOf(TType item)
        {
            int result = -1;
            //TODO: optimize to get it from query count

            int count = Count;
            for (int index = 0; index < count; index++)
            {
                if (Equals(this[index], item))
                {
                    result = index;
                    break;
                }
            }

            return result;

            ////TODO: optimize to get it from query
            //TupleList obj = DataProvider.RetrieveListItem(BlobDomain.EntityId, EntityId,
            //                                                                    item.EntityId);
            //return obj == null ? -1 : obj.Position;
        }

        public override void Insert(int index, TType item)
        {
            if ((uint) index > (uint) Count)
                throw new ArgumentOutOfRangeException("index");
            TupleList tuple = null;
            tuple = new TupleList(index, EntityId, item.GetType().FullName, item);

            DataProvider.AddEntityToCollection(Domain.EntityId, EntityId, index,
                                               tuple.FullyQualifiedType, tuple.Value);
            ++Version;
        }

        public override void InsertRange(int index, IEnumerable<TType> collection)
        {
            if (collection == null) return;
            if ((uint) index > (uint) Count) throw new ArgumentOutOfRangeException("index");

            int currIdx = index;
            ITupleList tuple = null;
            foreach (TType item in collection)
            {
                tuple = new TupleList(currIdx++, EntityId, item.GetType().FullName, item);


                DataProvider.AddEntityToCollection(Domain.EntityId, EntityId, tuple.Position,
                                                   tuple.FullyQualifiedType, tuple.Value);
            }
            ++Version;
        }

        #endregion
    }
}